package com.ld.security.common.elastic.base.service.impl;

import com.ld.security.common.core.base.po.ListPo;
import com.ld.security.common.core.base.po.PagePo;
import com.ld.security.common.core.base.po.SuperPo;
import com.ld.security.common.core.base.vo.PageVo;
import com.ld.security.common.core.util.ReflectionUtil;
import com.ld.security.common.core.util.TemplateUtil;
import com.ld.security.common.elastic.base.anno.EsKey;
import com.ld.security.common.elastic.base.constant.EsCondition;
import com.ld.security.common.elastic.base.model.SuperModel;
import com.ld.security.common.elastic.base.repository.SuperRepository;
import com.ld.security.common.elastic.base.service.ISearchService;
import com.ld.security.common.elastic.util.ElasticUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

public abstract class ISearchServiceImpl<E extends SuperModel> implements ISearchService<E> {

    @Autowired
    private SuperRepository<E> superRepository;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;



    @Override
    public PageVo<E> search(PagePo<String> po) {

        SearchResultMapper mapper =   ElasticUtil.newSearchResultMapper();
        PagePo<E> pp =this.newPagePo(po);

        AggregatedPage<E> page =  elasticsearchTemplate.queryForPage(    ElasticUtil.pageNativeSearchQuery(pp,true),this.getEntityClass(),mapper);
        return this.toPage(page);
    }



    PageVo<E> toPage(   Page<E> page){
        PageVo<E> vo = new PageVo();
        vo.setTotal(page.getTotalElements());
        vo.setList(page.getContent());
        return vo;
    }


    PagePo<E> newPagePo(   PagePo<String> po){
        PagePo<E> pp = po.newQuery();
        E e = this.newInstance();
        if(!TemplateUtil.isNull(po.getQuery())){
            ReflectionUtil.applyAllDeclaredFields(e,EsKey.class,(anno, name, val) -> {
                if(anno.value() == EsCondition.like){
                    ReflectionUtil.invokeSetter(e,name,po.getQuery());
                }
            });
        }

        pp.setQuery(e);
        return pp;
    }


    @Override
    public E getById(String id) {
        return superRepository.findById(id).get();
    }

    @Override
    public List<E> listByIds(Collection<String> ids) {
       return   superRepository.findByIdIn(ids);
    }

    @Override
    public E getOne(SuperPo query) {
        PagePo p = new PagePo<>();
        p.setQuery(query);

        List<E> list =  this.page(p).getList();

        return list.isEmpty()?null:list.get(0);
    }

    @Override
    public PageVo<E> page( SuperPo po) {



        Page<E> page = superRepository.search( ElasticUtil.pageNativeSearchQuery(po,false));

        return this.toPage(page);
    }

    @Override
    public List<E> all() {
        LinkedList linkedList = new LinkedList<>();
        for (E e : superRepository.findAll()) {
            linkedList.add(e);
        }
        return  linkedList;
    }

    @Override
    public List<E> all(SuperPo po) {
        ListPo p =   new ListPo<>();
        p.setQuery(po);
        Page<E> page = superRepository.search( ElasticUtil.listNativeSearchQuery(p,false));
        return page.getContent();
    }

    @Override
    public List<E> all(ListPo<E> po) {
        Page<E> page = superRepository.search( ElasticUtil.listNativeSearchQuery(po,false));

        return page.getContent();
    }

    @Override
    public int save(E entity) {
        superRepository.save(entity);
        return 1;
    }

    @Override
    public int saveBatch(Collection<E> entityList) {
        superRepository.saveAll(entityList);
        return entityList.size();
    }

    @Override
    public int remove(SuperPo query) {
        List<E> ids =  this.all(query);
        superRepository.deleteAll(ids);
        return ids.size();
    }

    @Override
    public int count(SuperPo query) {
        return this.all(query).size();
    }
}
